#include "engine.h"

#ifdef DEBUG
	#define NG_PACKAGE_ReadFromDisk true
#else
	#define NG_PACKAGE_ReadFromDisk false
#endif

ng::Engine* createEngine();
nc::IAppEventHandler *createAppEventHandler();

namespace {
	static ng::Engine *engine_ = nullptr;
	inline ng::Engine* theEngine() { if (!engine_) engine_ = createEngine(); return engine_; }
}

nc::IAppEventHandler *createAppEventHandler() {
	if (!engine_)
		engine_ = createEngine();
	return engine_;
}

namespace ng {

	bool ResourceMgr::addFont(const nt::String &name, nt::UniquePtr<nc::Font> &font) {
		if (name.isEmpty() || !font) return false;
		auto f = getFont(name);
		if (f) return false;
		font->setName(name);
		res_.font.pushBack(nt::move(font));
		return true;
	}
	void ResourceMgr::removeFont(const nt::String &name) {
		if (name.isEmpty()) return;
		for (auto it = res_.font.begin(); it != res_.font.end(); ++it) {
			if ((*it)->name() == name) {
				res_.font.erase(it);
				break;
			}
		}
	}
	void ResourceMgr::removeFont(const nc::Font *font) {
		if (!font) return;
		for (auto it = res_.font.begin(); it != res_.font.end(); ++it) {
			if ((*it).get() == font) {
				res_.font.erase(it);
				break;
			}
		}
	}
	void ResourceMgr::clearFont() { res_.font.clear(); }
	nc::Font* ResourceMgr::getFont(const nt::String &name) {
		if (name.isEmpty()) return nullptr;
		for (auto it = res_.font.begin(); it != res_.font.end(); ++it) {
			if ((*it)->name() == name) {
				return ((*it).get());
			}
		}
		return nullptr;
	}

 	bool ResourceMgr::addTexture(const nt::String &name, nt::UniquePtr<nc::Texture> &texture) {
		if (name.isEmpty() || !texture) return false;
		auto t = getTexture(name);
		if (t) return false;
		texture->setName(name);
		res_.texture.pushBack(nt::move(texture));
		return true;
	}
	void ResourceMgr::removeTexture(const nt::String &name) {
		if (name.isEmpty()) return;
		for (auto it = res_.texture.begin(); it != res_.texture.end(); ++it) {
			if ((*it)->name() == name) {
				res_.texture.erase(it);
				break;
			}
		}
	}
	void ResourceMgr::removeTexture(const nc::Texture *texture) {
		if (!texture) return;
		for (auto it = res_.texture.begin(); it != res_.texture.end(); ++it) {
			if ((*it).get() == texture) {
				res_.texture.erase(it);
				break;
			}
		}
	}
	void ResourceMgr::clearTexture() { res_.texture.clear(); }
	nc::Texture* ResourceMgr::getTexture(const nt::String &name) {
		if (name.isEmpty()) return nullptr;
		for (auto it = res_.texture.begin(); it != res_.texture.end(); ++it) {
			if ((*it)->name() == name) {
				return ((*it).get());
			}
		}
		return nullptr;
	}

 	bool ResourceMgr::addAudio(const nt::String &name, nt::UniquePtr<nc::AudioStreamPlayer> &player) {
		if (name.isEmpty() || !player) return false;
		auto a = getAudio(name);
		if (a) return false;
		player->setName(name);
		res_.audio.pushBack(nt::move(player));
		return true;
	}
	bool ResourceMgr::addAudio(const nt::String &name, nt::UniquePtr<nc::AudioBufferPlayer> &player) {
		if (name.isEmpty() || !player) return false;
		auto a = getAudio(name);
		if (a) return false;
		player->setName(name);
		res_.audio.pushBack(nt::move(player));
		return true;
	}
	void ResourceMgr::removeAudio(const nt::String &name) {
		if (name.isEmpty()) return;
		for (auto it = res_.audio.begin(); it != res_.audio.end(); ++it) {
			if ((*it)->name() == name) {
				res_.audio.erase(it);
				break;
			}
		}
	}
	void ResourceMgr::removeAudio(const nc::IAudioPlayer *player) {
		if (!player) return;
		for (auto it = res_.audio.begin(); it != res_.audio.end(); ++it) {
			if ((*it).get() == player) {
				res_.audio.erase(it);
				break;
			}
		}
	}
	void ResourceMgr::clearAudio() { res_.audio.clear(); }
	nc::IAudioPlayer* ResourceMgr::getAudio(const nt::String &name) {
		if (name.isEmpty()) return nullptr;
		for (auto it = res_.audio.begin(); it != res_.audio.end(); ++it) {
			if ((*it)->name() == name) {
				return ((*it).get());
			}
		}
		return nullptr;
	}

	//////////////////////////////////
	Scene::Scene() {}

	nc::Font* Scene::getFont(const nt::String &name) {
		auto f = ResourceMgr::getFont(name);
		if (f) return f;
		return theEngine()->getFont(name);
	}
	nc::Texture* Scene::getTexture(const nt::String &name) {
		auto t = ResourceMgr::getTexture(name);
		if (t) return t;
		return theEngine()->getTexture(name);
	}
	nc::IAudioPlayer* Scene::getAudio(const nt::String &name) {
		auto a = ResourceMgr::getAudio(name);
		if (a) return a;
		return theEngine()->getAudio(name);
	}

	void Scene::enterScene() {}
	void Scene::exitScene() {}

	void Scene::setAttribute(const char *name, const char *value) {}
	bool Scene::loadXmlFile(const nt::String &file) { return false; }
	bool Scene::loadXmlBuffer(const char *buffer, unsigned len) { return false; }
	bool Scene::loadXml(const tinyxml2::XMLElement *ele) { return false; }

	//////////////////////////////////
	Engine::Engine() : package_(NG_PACKAGE_ReadFromDisk) {}
	Engine::~Engine() {}

	Package& Engine::package() { return package_; }
	void Engine::addScene(Scene *scene) {}
	void Engine::removeScene(Scene *scene) {}
	void Engine::changeScene(Scene *scene) {}

	void Engine::setAttribute(const char *name, const char *value) {}
	bool Engine::loadXmlFile(const nt::String &file) { return false; }
	bool Engine::loadXmlBuffer(const char *buffer, unsigned len) { return false; }
} // end namespace ng